//==========================================================================
// Copyright (c) 2000-2008,  Elastos, Inc.  All Rights Reserved.
//==========================================================================

#include <mantle.h>

// Interface functions
//
PInterface CReaderWriterLock::Probe(
    /* [in] */ REIID riid)
{

    if (riid == EIID_IInterface) {
        return (PInterface)(IReaderWriterLock *)this;
    }
    else if (riid == EIID_IReaderWriterLock) {
        return (IReaderWriterLock *)this;
    }
    else if (riid == EIID_CLASS_INFO) {
        return (PInterface)&ECLSID_CReaderWriterLock;
    }
    else if (riid == EIID_INTERFACE_INFO) {
        return (PInterface)&EIID_IReaderWriterLock;
    }

    return NULL;
}

UInt32 CReaderWriterLock::AddRef(void)
{
    return (UInt32)m_cRef.Increment();
}

UInt32 CReaderWriterLock::Release(void)
{
    Int32 nRef = m_cRef.Decrement();

    if (nRef == 0) {
        delete this;
    }
    return (UInt32)nRef;
}

ECode CReaderWriterLock::Aggregate(
    /* [in] */ AggregateType type,
    /* [in] */ PInterface pObj)
{
    return E_NOT_IMPLEMENTED;
}

ECode CReaderWriterLock::GetDomain(
    /* [out] */ PInterface *ppObj)
{
    return E_NOT_IMPLEMENTED;
}

ECode CReaderWriterLock::ReaderLock(WaitResult *pResult)
{
    if (NULL == pResult) return E_INVALID_ARGUMENT;

    Boolean bIsHeld;

    m_krwlock.IsReaderLockHeld(&bIsHeld);
    if (bIsHeld) return E_ALREADY_LOCKED;

    m_krwlock.IsWriterLockHeld(&bIsHeld);
    if (bIsHeld) return E_INVALID_LOCK;

    if (!CanAcquireReaderLock()) return E_READER_LOCKS_TOO_MANY;

    m_krwlock.ReaderLock(pResult);
    return NOERROR;
}

ECode CReaderWriterLock::ReaderTryLock(
    /* [in] */ Millisecond32 msTimeout,
    /* [out] */ WaitResult *pResult)
{
    if (NULL == pResult) return E_INVALID_ARGUMENT;

    Boolean bIsHeld;

    m_krwlock.IsReaderLockHeld(&bIsHeld);
    if (bIsHeld) return E_ALREADY_LOCKED;

    m_krwlock.IsWriterLockHeld(&bIsHeld);
    if (bIsHeld) return E_INVALID_LOCK;

    if (!CanAcquireReaderLock()) return E_READER_LOCKS_TOO_MANY;

    m_krwlock.ReaderTryLock(DzMillisecondsToTicks(msTimeout), pResult);
    return NOERROR;
}

ECode CReaderWriterLock::ReaderUnlock()
{
    Boolean bIsHeld;
    m_krwlock.IsReaderLockHeld(&bIsHeld);
    if (!bIsHeld) return E_NOT_READER;

    m_krwlock.ReaderUnlock();
    return NOERROR;
}

ECode CReaderWriterLock::UpgradeToWriter(WaitResult *pResult)
{
    if (NULL == pResult) return E_INVALID_ARGUMENT;

    Boolean bIsHeld;
    m_krwlock.IsReaderLockHeld(&bIsHeld);
    if (!bIsHeld) return E_NOT_READER;

    m_krwlock.UpgradeToWriter(pResult);
    return NOERROR;
}

ECode CReaderWriterLock::TryUpgradeToWriter(
    /* [in] */ Millisecond32 msTimeout,
    /* [out] */ WaitResult *pResult)
{
    if (NULL == pResult) return E_INVALID_ARGUMENT;

    Boolean bIsHeld;
    m_krwlock.IsReaderLockHeld(&bIsHeld);
    if (!bIsHeld) return E_NOT_READER;

    m_krwlock.TryUpgradeToWriter(DzMillisecondsToTicks(msTimeout), pResult);
    return NOERROR;
}

ECode CReaderWriterLock::WriterLock(WaitResult *pResult)
{
    if (NULL == pResult) return E_INVALID_ARGUMENT;

    Boolean bIsHeld;
    m_krwlock.IsWriterLockHeld(&bIsHeld);
    if (bIsHeld) return E_ALREADY_LOCKED;

    m_krwlock.IsReaderLockHeld(&bIsHeld);
    if (bIsHeld) return E_INVALID_LOCK;

    m_krwlock.WriterLock(pResult);
    return NOERROR;
}

ECode CReaderWriterLock::WriterTryLock(
    /* [in] */ Millisecond32 msTimeout,
    /* [out] */ WaitResult *pResult)
{
    if (NULL == pResult) return E_INVALID_ARGUMENT;

    Boolean bIsHeld;
    m_krwlock.IsWriterLockHeld(&bIsHeld);
    if (bIsHeld) return E_ALREADY_LOCKED;

    m_krwlock.IsReaderLockHeld(&bIsHeld);
    if (bIsHeld) return E_INVALID_LOCK;

    m_krwlock.WriterTryLock(DzMillisecondsToTicks(msTimeout), pResult);
    return NOERROR;
}

ECode CReaderWriterLock::WriterUnlock()
{
    Boolean bIsHeld;
    m_krwlock.IsWriterLockHeld(&bIsHeld);
    if (!bIsHeld) return E_NOT_WRITER;

    m_krwlock.WriterUnlock();
    return NOERROR;
}

ECode CReaderWriterLock::DowngradeFromWriter()
{
    Boolean bIsHeld;
    m_krwlock.IsWriterLockHeld(&bIsHeld);
    if (!bIsHeld) return E_NOT_WRITER;

    if (!CanAcquireReaderLock()) return E_READER_LOCKS_TOO_MANY;

    m_krwlock.DowngradeFromWriter();
    return NOERROR;
}

ECode CReaderWriterLock::IsReaderLockHeld(Boolean*pIsHeld)
{
    if (NULL == pIsHeld) return E_INVALID_ARGUMENT;

    m_krwlock.IsReaderLockHeld(pIsHeld);
    return NOERROR;
}

ECode CReaderWriterLock::IsWriterLockHeld(Boolean *pIsHeld)
{
    if (NULL == pIsHeld) return E_INVALID_ARGUMENT;

    m_krwlock.IsWriterLockHeld(pIsHeld);
    return NOERROR;
}
